// Jeremy Lee
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace RobotWalk
{
    public static class Globl
    {
        public const int SCREEN_WIDTH = 800;
        public const int SCREEN_HEIGHT = 600;
    }
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        const int TARGET_FPS = 30;
        Robot robot;
        int currentSpeed;
        int prevMouseWheel;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            IsFixedTimeStep = true;
            TargetElapsedTime = new TimeSpan(0, 0, 0, 0, 1000 / TARGET_FPS);
            graphics.PreferredBackBufferWidth = Globl.SCREEN_WIDTH;
            graphics.PreferredBackBufferHeight = Globl.SCREEN_HEIGHT;
            graphics.PreferMultiSampling = false;
            graphics.ApplyChanges();
            currentSpeed = 2;
            prevMouseWheel = 0;
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            Texture2D spriteL = Content.Load<Texture2D>("media\\left");
            Texture2D spriteR = Content.Load<Texture2D>("media\\right");
            robot = new Robot(spriteL, spriteR);
        }

        protected override void UnloadContent(){}

        protected override void Update(GameTime gameTime)
        {
            GamePadState gs = GamePad.GetState(PlayerIndex.One);
            KeyboardState ks = Keyboard.GetState();
            MouseState ms = Mouse.GetState();
            if (gs.IsButtonDown(Buttons.Back)||ks.IsKeyDown(Keys.Escape))
                this.Exit();
            if (gs.Triggers.Left > 0.05 || ks.IsKeyDown(Keys.Left) || ms.LeftButton == ButtonState.Pressed)
                robot.moveLeft();
            if (gs.Triggers.Right > 0.05 || ks.IsKeyDown(Keys.Right) || ms.RightButton == ButtonState.Pressed)
                robot.moveRight();
            if (ks.IsKeyDown(Keys.Space) || ms.MiddleButton == ButtonState.Pressed)
                robot.fire();
            if (ks.IsKeyDown(Keys.D1))
                currentSpeed = 1;
            if (ks.IsKeyDown(Keys.D2))
                currentSpeed = 2;
            if (ks.IsKeyDown(Keys.D3))
                currentSpeed = 3;
            if (ks.IsKeyDown(Keys.D4))
                currentSpeed = 4;
            if (ks.IsKeyDown(Keys.D5))
                currentSpeed = 5;
            if (ks.IsKeyDown(Keys.D6))
                currentSpeed = 6;
            if (ks.IsKeyDown(Keys.D7))
                currentSpeed = 7;
            if (ks.IsKeyDown(Keys.D8))
                currentSpeed = 8;
            if (ks.IsKeyDown(Keys.D9))
                currentSpeed = 9;
            if (ks.IsKeyDown(Keys.D0))
                currentSpeed = 10;
            if (ms.ScrollWheelValue > prevMouseWheel)
            {
                currentSpeed++;
                prevMouseWheel = ms.ScrollWheelValue;
            }
            if (ms.ScrollWheelValue < prevMouseWheel)
            {
                currentSpeed--;
                prevMouseWheel = ms.ScrollWheelValue;
            }
            int tmp = 1 + 10 * (int)gs.Triggers.Left;
            tmp += 1 + 10 * (int)gs.Triggers.Right;
            if (gs.IsConnected && tmp != 0)
                currentSpeed = tmp;
            if (currentSpeed < 1)
                currentSpeed = 1;
            if (currentSpeed > 10)
                currentSpeed = 10;
            robot.speed((float)currentSpeed * 0.25f);
            robot.update(gameTime.ElapsedGameTime.TotalSeconds);
            //System.Diagnostics.Debug.Write("Mouse Wheel: " + ms.ScrollWheelValue + "\n");
            //System.Diagnostics.Debug.Write("Speed: " + currentSpeed + "\n");
            //System.Diagnostics.Debug.Write("Keyboard State: " );
            //foreach( Keys k in ks.GetPressedKeys() )
            //    System.Diagnostics.Debug.Write(k.ToString());
            //System.Diagnostics.Debug.Write("\n");
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);
            robot.draw(spriteBatch);
            base.Draw(gameTime);
        }
    }
    enum RobotState
    {
        STOP_LEFT = 0,
        STOP_RIGHT = 1,
        WALK_LEFT = 2,
        WALK_RIGHT = 3,
        FIRE_LEFT = 4,
        FIRE_RIGHT = 5,
    }
    public class Robot
    {
        Texture2D leftSprite, rightSprite;
        Vector2 loc;
        Vector2 vel;
        RobotState state;
        Rectangle[] animateRect;
        int[][] animateSequence;
        int frameCount;
        double timer;
        const double frameRate = 5.0 / 30.0;
        float speedFactor;
        const float baseSpeed = 25.0f;
        float MAX_SPEED = 100.0f;
        double fireTime;

        public Robot( Texture2D leftTex, Texture2D rightTex )
        {
            leftSprite = leftTex;
            rightSprite = rightTex;
            loc = new Vector2((float)Globl.SCREEN_WIDTH / 2.0f, (float)Globl.SCREEN_HEIGHT / 2.0f-39.0f);
            vel = Vector2.Zero;
            state = RobotState.STOP_LEFT;
            animateRect = new Rectangle[6];
            for (int i = 0; i < 4; i++)
                animateRect[i] = new Rectangle(2+(74 * i), 1, 68, 78);
            animateRect[4] = new Rectangle(1, 83, 68, 78);
            animateRect[5] = new Rectangle(74, 83, 68, 78);
            animateSequence = new int[3][];
            animateSequence[0] = new int[] { 0 };                       // Stop sequence
            animateSequence[1] = new int[] { 0, 1, 2, 4, 2, 1 };        // Walk sequence
            animateSequence[2] = new int[] { 0, 1, 3, 4, 5, 4, 2, 1 };  // Fire sequence
            speedFactor = 0.5f;
            fireTime = 0.0;
        }
        public void moveLeft()
        {
            vel.X -= baseSpeed * speedFactor;
            state = RobotState.WALK_LEFT;
        }
        public void moveRight()
        {
            vel.X += baseSpeed * speedFactor;
            state = RobotState.WALK_RIGHT;
        }
        public void fire()
        {
            if (frameCount > animateSequence[2].Length)
                frameCount = 0;
            if ((int)state % 2 == 0)
                state = RobotState.FIRE_LEFT;
            else
                state = RobotState.FIRE_RIGHT;
            fireTime = 1.33;
        }
        public void speed(float val)
        {
            speedFactor = val;
            MAX_SPEED = baseSpeed * 8.0f * val;
        }
        public void update(double elapsedTime)
        {
            if (fireTime >= 0.0)
            {
                fireTime -= elapsedTime;
            }
            else
            {
                if ((int)state >= 4)
                {
                    if ((int)state % 2 == 0)
                        state = RobotState.STOP_LEFT;
                    else
                        state = RobotState.STOP_RIGHT;
                    frameCount = 0;
                }
                vel *= 0.95f;
                if (vel.Length() < 5.0f)
                {
                    vel = Vector2.Zero;
                    if ((int)state % 2 == 0)
                        state = RobotState.STOP_LEFT;
                    else
                        state = RobotState.STOP_RIGHT;
                    frameCount = 0;
                }
                if (vel.Length() > MAX_SPEED)
                    vel *= MAX_SPEED / vel.Length();
                loc.X += vel.X * (float)elapsedTime;
                if (loc.X <= 0.0f)
                {
                    loc.X = 0.0f;
                    vel.X = 0.0f;
                    state = RobotState.STOP_LEFT;
                    frameCount = 0;
                }
                if (loc.X >= (float)Globl.SCREEN_WIDTH - 68.0f)
                {
                    loc.X = (float)Globl.SCREEN_WIDTH - 68.0f;
                    vel.X = 0.0f;
                    state = RobotState.STOP_RIGHT;
                    frameCount = 0;
                }
            }
            timer -= elapsedTime;
            if (timer <= 0.0)
            {
                timer = frameRate;
                frameCount++;
                frameCount = frameCount % (animateSequence[(int)state / 2].Length);
            }
        }
        public void draw(SpriteBatch sb)
        {
            
            sb.Begin();
            if ((int)state % 2 == 0)
                sb.Draw(rightSprite, loc, animateRect[animateSequence[(int)state/2][frameCount]], Color.White);
            else
                sb.Draw(leftSprite, loc, animateRect[animateSequence[(int)state/2][frameCount]], Color.White);
            sb.End();
        }
    }
}
